package Java8新特性;

import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;

/*
    函数式(Functional)接口
         只包含一个抽象方法的接口,称为函数式接口
         可以通过 Lambda 表达式来创建该接口的对象,(若 Lambda 表达式抛出一个受检异常(即:非运行时异常)那么该异常需要在目标接口的抽象方法上进行声明)
         可以在一个接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口
         在java.util.function包下定义了Java 8 的丰富的函数式接口

    如何理解函数式接口
          Java从诞生日起就是一直倡导"一切皆对象",在Java里面面向对象(OOP)编程是一切,但是随着python、scala等语言的兴起和新技术的挑战,Java不得不做出调整以便支持更加广泛的技术要求,也即java不但可以支持OOP还可以支持OOF(面向函数编程)
          在函数式编程语言当中,函数被当做一等公民对待,在将函数作为一等公民的编程语言中,Lambda表达式的类型是函数,但是在Java8中,有所不同,在 Java8中,Lambda表达式是对象,而不是函数,它们必须依附于一类特别的对象类型-->函数式接口
          在Java8中, Lambda 表达式就是一个函数式接口的实例,这就是 Lambda 表达式和函数式接口的关系,也就是说,只要一个对象是函数式接口的实例,那么该对象就可以用 Lambda 表达式来表示
          所以以前用匿名实现类表示的现在都可以用 Lambda 表达式来写

    Java 内置四大核心函数式接口
        消费型接口 Consumer<T>     void accept(T t)
        供给型接口 Supplier<T>     T get()
        函数型接口 Function<T, R>  R apply(T t)
        断定型接口 Predicate<T>    boolean test(T t)
 */
public class FunctionalInterface02 {
    //调用消费型接口
    @Test
    public void test1(){
        //原始写法
        this.happyTime(500, new Consumer<Double>() {
            @Override
            public void accept(Double aDouble) {
                System.out.println(aDouble);
            }
        });

        //Lambda写法
        this.happyTime(500,aDouble -> System.out.println(aDouble));
    }

    //消费型接口
    public void happyTime(double money, Consumer<Double> con){
        con.accept(money);
    }

    //调用断定型接口
    @Test
    public void test2(){

        List<String> list = Arrays.asList("南京","北京","天津","东京","西京");

        //原始写法
        List<String> filterList = this.filterString(list, new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.contains("京");
            }
        });
        System.out.println(filterList);

        //Lambda写法
        filterList = this.filterString(list,s -> s.contains("京"));
        System.out.println(filterList);
    }

    //断定型接口:根据给定的规则,过滤集合中的字符串,此规则由Predicate的方法决定
    public List<String> filterString(List<String> list, Predicate<String> pre){
        List<String> filterList = new ArrayList<>();

        for(String s : list){
            if(pre.test(s)){
                filterList.add(s);
            }
        }

        return filterList;
    }
}
